﻿using System;
using System.ServiceModel;
using System.IdentityModel.Claims;
using System.IdentityModel.Policy;
using System.Collections.Generic;
using System.IdentityModel.Tokens;


namespace RelyingPartyService
{
    public class ClaimProcessing : ServiceAuthorizationManager 
    {
        public override bool CheckAccess(OperationContext operationContext)
        {
			if (operationContext.IncomingMessageHeaders.Action == "http://schemas.xmlsoap.org/ws/2004/09/transfer/Get")
				return true;
			
            if (operationContext.IncomingMessageHeaders.Action == "http://tempuri.org/IRPServiceTest1/Test1")
                return true;

			if (operationContext.IncomingMessageHeaders.Action != "http://tempuri.org/IRPServiceTest2/Test2"
				&& operationContext.IncomingMessageHeaders.Action != "http://tempuri.org/IRPServiceTest3/Test3"
				&& operationContext.IncomingMessageHeaders.Action != "http://tempuri.org/IRPServiceTest4/Test4")
					return false;

            AuthorizationContext authContext = operationContext.ServiceSecurityContext.AuthorizationContext;

            if (authContext.ClaimSets == null)
                return false;

            List<ClaimSet> claimsets = new List<ClaimSet>(authContext.ClaimSets);
            ClaimSet myClaimSet = claimsets.Find((Predicate<ClaimSet>)delegate(ClaimSet target)
            {
				return (target.Issuer as X509CertificateClaimSet) != null;
            });

			// If the ClaimSet was NOT issued by a trusted STS then return false (Access Denied)
			if (!IssuedByTrustedSTS(myClaimSet))
				return false;

			if (operationContext.IncomingMessageHeaders.Action == "http://tempuri.org/IRPServiceTest3/Test3"
				|| operationContext.IncomingMessageHeaders.Action == "http://tempuri.org/IRPServiceTest4/Test4")
			{
				IEnumerable<Claim> authClaims = myClaimSet.FindClaims(ClaimTypes.AuthorizationDecision, Rights.PossessProperty);

				if (authClaims == null)
					return false;

				foreach (Claim claim in authClaims)
				{
					if (!claim.Resource.Equals("ok"))
						return false;
				}
				return true;
			}
			else
			{
				IEnumerable<Claim> emailClaims = myClaimSet.FindClaims(ClaimTypes.Email, Rights.PossessProperty);

				if (emailClaims == null)
					return false;

				foreach (Claim claim in emailClaims)
				{
					string authorizedEMail = claim.Resource.ToString();
					if (authorizedEMail == "jhfigueiredo@netvisao.pt")
						return true;
				}
			}
			return false;
		}

		#region IssuedByTrustedSTS
		/// <summary>
		/// Helper function to check if claims were issued by the trusted STS
		/// </summary>
		/// <returns>True on success. False on failure.</returns>
		private static bool IssuedByTrustedSTS(ClaimSet myClaimSet)
		{
			if (myClaimSet.Issuer == null)
				return false;

			// Find all the Thumbprint claims in the issuer ClaimSet
			IEnumerable<Claim> issuerClaims = myClaimSet.Issuer.FindClaims(ClaimTypes.Thumbprint, null);

			if (issuerClaims == null)
				return false;

			// Get the enumerator for the set of Thumbprint claims...                        
			IEnumerator<Claim> issuerClaimsEnum = issuerClaims.GetEnumerator();

			// ...and set issuerClaim to the first such Claim
			Claim issuerClaim = null;
			if (issuerClaimsEnum.MoveNext())
				issuerClaim = issuerClaimsEnum.Current;

			// If there was no Thumbprint claim, return false;
			if (issuerClaim == null)
				return false;

			// If, despite the above checks, the returned claim is not a Thumbprint claim, return false
			if (issuerClaim.ClaimType != ClaimTypes.Thumbprint)
				return false;

			// If the returned claim doesn't contain a Resource, return false
			if (issuerClaim.Resource == null)
				return false;

			// Extract the thmubprint data from the claim
			byte[] thumbprint = (byte[])issuerClaim.Resource;

			// Extract the thumbprint for the BookStoreSTS.com certificate
			byte[] issuerCertThumbprint = ((X509SecurityToken)RelyingPartyService.RpConfiguration.Current.GetStsToken(
				new EndpointAddress("http://neptune:9000/STSConsoleImpleSample/STSImplSample/"))).Certificate.GetCertHash();

			// If the lengths of the two thumbprints are different, return false
			if (thumbprint.Length != issuerCertThumbprint.Length)
				return false;

			// Check the individual bytes of the two thumbprints for equality...
			for (int i = 0; i < thumbprint.Length; i++)
				if (thumbprint[i] != issuerCertThumbprint[i])
					return false;

			return true;
		}

		#endregion
    }
}
